using System;
using System.Collections.Generic;
using System.Text;

namespace GameEditor.Common
{
    public sealed class Functional
    {
        private Functional()
        {
        }


        public static Predicate<T> AlwaysTrue<T>()
        {
            return new Predicate<T>(delegate(T obj) { return true; });
        }
        public static Predicate<T> AlwaysFalse<T>()
        {
            return new Predicate<T>(delegate(T obj) { return false; });
        }
        public static Converter<T, T> Identity<T>()
        {
            return new Converter<T, T>(delegate(T a) { return a; });
        }


        public static IEnumerable<TOutput> Map<TInput, TOutput>(Converter<TInput, TOutput> transform, IEnumerable<TInput> sequence)
        {
            foreach (TInput input in sequence)
            {
                yield return transform(input);
            }
        }
        public static IEnumerable<T> Filter<T>(Predicate<T> predicate, IEnumerable<T> sequence)
        {
            foreach (T input in sequence)
            {
                if (predicate(input))
                    yield return input;
            }
        }

        public static T Reduce<T>(DelegateWithReturnValue<T, T, T> fun, IEnumerable<T> sequence, T initial)
        {
            T ret = initial;
            foreach (T input in sequence)
            {
                ret = fun(ret, input);
            }
            return ret;
        }
        public static IEnumerable<T> From<T>(T[] sequence, int index)
        {
            for (int i = index; i < sequence.Length; i++)
                yield return sequence[i];
        }
        public static IEnumerable<T> From<T>(IEnumerable<T> sequence, int index)
        {
            int i = 0;
            foreach (T t in sequence)
            {
                if (i > index)
                    yield return t;
                i++;                
            }
        }
        public static IEnumerable<T> Take<T>(IEnumerable<T> sequence, int index, int length)
        {
            int i = 0;
            foreach (T t in sequence)
            {
                if (length <= 0)
                    break;
                if (i > index)
                {
                    length--;
                    yield return t;
                }
                i++;
            }
        }
        public static IEnumerable<int> Range(int upperBound)
        {
            for (int i = 0; i < upperBound; i++)
            {
                yield return i;
            }
        }
        public static IEnumerable<int> Range(int lowerBound, int upperBound)
        {
            for (int i = lowerBound; i < upperBound; i++)
                yield return i;
        }


    }
}
